package com.lzp.java.concurrent.buildcache;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * @author lzp
 * @Description: 1. 引入Future解决重复计算问题，并使用map
 * @date 2021/3/14
 */
public class Cache4<K, V> implements Computable<K, V> {
    private final Map<K, Future<V>> cache = new ConcurrentHashMap<>();
    private final Computable<K, V> c;

    public Cache4(Computable<K, V> c) {
        this.c = c;
    }

    @Override
    public V compute(K key) throws Exception {
        Future<V> result = cache.get(key);
        if (result == null) {
            FutureTask<V> futureTask = new FutureTask<V>(() -> {
                return c.compute(key);
            });
            // 此时task还未计算，先占位
            result = futureTask;
            // 作用：1. 设置值，保持其他线程可见，保证result == null后不重复。
            // 2. 防止多线程result == null时，如果有key则不设值。
            result = cache.putIfAbsent(key, result);
            if (result == null) {
                result = futureTask;
                futureTask.run();
            }
        }
        return result.get();
    }

    public static void main(String[] args) throws Exception {
        Cache4<String, Integer> cache1 = new Cache4<>(new ComputableImpl());
        System.out.println(cache1.compute("key"));
        System.out.println(cache1.compute("key"));
    }
}
